﻿/*******************************************************************************
 **  Name:                                        **
 **  Description:                                                             **
 **                                                                           **
 **  CDDL: Open Source Initiative (OSI) Approved License                            **
 **                                                                           **
 **  Copyright (c) 2009-2010 Barry "Gian" James  <bjames@munixos.net>         **
 **  All rights reserved.                                                     **
 **                                                                           **
 **  The contents of this file are subject to the terms of the CDDL:          **
 **  Common Development and Distribution License (the "License").             **
 **  You may not use this file except in compliance with the License.         **
 **                                                                           **
 **  You can obtain a copy of the license at $PROJECT_ROOT/LICENSE            **
 **  or http://www.opensolaris.org/os/licensing.  This code is Open Source    **
 **  and you are free to use it within the confines of the license, even      **
 **  for your own closed-source commercial projects, as long as you follow    **
 **  the terms set forth in the CDDL.                                         **
 **                                                                           **
 **  When distributing Covered Code, include this CDDL HEADER in each         **
 **  file and include the License file at $PROJECT_ROOT/LICENSE.              **
 **  If applicable, add the following below this CDDL HEADER, with the        **
 **  fields enclosed by brackets "[]" replaced with your own identifying      **
 **  information: Portions Copyright [yyyy] [name of copyright owner]         **
 **                                                                           **
 ******************************************************************************/
// Created on November 1, 2010, 7:25 AM
// Modified $Date$ by $Author$
// $Id$

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Xml;
using System.Xml.Linq;
using System.Threading;

namespace sat1baf1
{

    class CmdProc
    {        
        public enum CLType { Login, Passwd, Request, Search, Table, Tell, Help, Codeword, Cmds };

        private int cmd = 0;
        private Socket s;
        private string CmdPrompt = "? ";
        private MainForm.AgentSock sp;
        private MainForm _form;

        public CmdProc(MainForm.AgentSock socpkt)
        {
	//		cmd = socpkt.cmd;
			s = socpkt.sock;
            sp = socpkt;
            _form = null;
        }

        public bool Process()
        {
            string scmd = sp.cmdArgs.ToString();
            string[] args = scmd.Split(' ');
            switch (args[0])
            {
                case "search":
                    if (args.Count() <= 2)
                    {
                        Send(s, "search <asset> <search string>\r\n");
                        Send(s, CmdPrompt);
                        break;
                    }                    
                    XmlLog.Instance.Add("CmdProc:Process(\"search\"): " + args[1]);

                    // check clearance TODO
                    bool IsAuthorized = false;
                    var elems =
                        from a in (CLIDB.Instance.Elements).Elements("SEARCHES")
                        //where a.Elements("SEARCH").Attributes("db").Equals(args[1])
                        select a;
                    foreach (var el in elems.Elements("SEARCH"))
                    {
                        //XmlLog.Instance.Add("CmdProc:el " + el);
                        if (((string)el.Attribute("db")).Contains(args[1]))
                        {
                            XmlLog.Instance.Add("CmdProc:el " + el);

                            XmlLog.Instance.Add("CmdProc:el " + el.Element("NAME").Value);
                            if (((string)el.Element("NAME")).Contains(args[2]))
                            {
                                var acl =
                                    from z in el.Elements("ACL").Elements("AUTH")
                                    select z;
                                string [] acls = new string[5];
                                byte idx = 0;
                                foreach (var e in acl)
                                {
                                    acls[idx++] = (string)e;
                                    XmlLog.Instance.Add(String.Format("CmdProc: ACL check: {0} vs {1}", (string)e, GetClearance(sp.agent)));
                                }
                                Send(s, "You have ");
                                if (HasClearance(sp.agent, acls))
                                    SendLine("SUFFICIENT clearance");
                                else
                                    SendLine("INSUFFICIENT clearance");
                                SendLine(s, "[" + GetClearance(sp.agent) + "] " + (string)el.Element("DATA"));
                            }
                        }
                        XmlLog.Instance.Add("CmdProc: el.Attribute(db)=" + (string)el.Attribute("db"));
                    }

                    Send(s, "Searching...\r\n");
                    if (args[2] == "matthias")
                    {
                        Send(s, "That information is restricted.\r\n");
                        Send(s, "Authorization ACCEPTED.\r\n");
                        SendDossier(args[2]);
                    }
                    else if (args[2] == "all")
                    {
                        var agents =
                            from a in AgentDB.Instance.AllAgents.Elements()
                            select a;
                        Send(s, String.Format("{0,-25} {1,-16} {2,-13}\r\n", "Name", "Primary Career", "Career Level"));
                        foreach (var el in agents)
                        {
                            Send(s,String.Format("{0,-25} {1,-16} {2,-13}\r\n",
                                el.Element("Name").Value,el.Element("Role").Value,el.Element("CareerLevel").Value));
                            //Send(s,"Found " + el + "\r\n");

                        }
                    }
                    Send(s, CmdPrompt);
                    break;

                case "request":
                    XmlLog.Instance.Add("CmdProc:Process(\"request\")");
                    Send(s, CmdPrompt);
                    break;
                case "table":
                    XmlLog.Instance.Add("CmdProc:Process(\"table\")");
                    Send(s, CmdPrompt);
                    break;

                case "codeword":
                    if (args.Count() != 2)
                    {
                        Send(s, "codeword <codeword>\r\n");
                        Send(s, "This attempt has been recorded\r\n");
                        Send(s, CmdPrompt);
                        break;
                    }
                    XmlLog.Instance.Add("CmdProc:Process(\"search\"): " + args[1]);
                    Send(s, "SAP Codeword " + args[1] + " for " + sp.agent + " set.\r\n");

                    XmlLog.Instance.Add("CmdProc:Process(\"table\")");
                    Send(s, CmdPrompt);
                    break;


                case "quit":
                    XmlLog.Instance.Add("CmdProc:Process(\"quit\")");
                    Send(s, CmdPrompt);
                    Send(s, "Processing your logout. Scrubbing your data...\r\n");
                    //for (int x = 5; x < 0; x--)
                    //{
                    //    Send(s, x.ToString() + " ");
                    //    Thread.Sleep(1000);
                    //}
                    //MainForm.DisconnectFromServer(sp);
                    _form.DisconnectFromServer(sp.idx);

                    break;

                case "help":
                    XmlLog.Instance.Add("CmdProc:Process(\"help\")");
                    CmdHelp();
                    Send(s, CmdPrompt);
                    break;
                case "who":
                    XmlLog.Instance.Add("CmdProc:Process(\"who\")");
                    Send(s, CmdPrompt);
                    break;

                case "roll":
                    XmlLog.Instance.Add("CmdProc:Process(\"roll\")("+args.Count() +")");
                    if (args.Count() != 2)
                    {
                        Send(s, "roll <die type>\r\n");
                        Send(s, CmdPrompt);
                        break;
                    }
                    Random rand = new Random((int)DateTime.Now.ToBinary());
                    Send(s,"Rolled: " + (rand.Next() % System.Convert.ToInt32(args[1])) + " out of " + args[1] + "\r\n");
                    Send(s, CmdPrompt);

                    break;

    
                default:
                    Send(s, "Unknown or unauthorized command.\r\n");
                    Send(s, CmdPrompt);
                    break;

                //case (int)CmdList.Login:
                    //string uname = sp.sb.ToString();
                    //sp.m_currAgent.Cmd = 1;
                    
                    ////Send(s,"Password:");
                    //byte [] byData = System.Text.Encoding.ASCII.GetBytes("Password: ");
                    //s.Send(byData);
                    //s.Receive(byData);
                    //string passwd = Encoding.ASCII.GetString(byData);
                    //if (passwd == "newlife8")
                    //{
                    //    Send(s, "OK");
                    //    Send(s, CmdPrompt);
                    //}
                //    break;
            }
            return true;
        }

        public bool HasClearance(string agent, string [] acl) 
        {
            
            foreach (string e in acl)
            {
                if ((string)e == null) break;
                XmlLog.Instance.Add(String.Format("HasClearance: ACL check: {0} vs {1}", (string)e, GetClearance(sp.agent)));
                if (    (string)e == GetClearance(sp.agent) || 
                        ( Char.IsNumber(e[0]) 
                            && System.Convert.ToInt16((string)e) <= System.Convert.ToInt16(GetClearance(sp.agent)))
                    )
                    return true;
            }

            return false; 
        }
        public string GetClearance(string agent) 
        {
            IEnumerable<XElement> agents = AgentDB.Instance.FindAgentByCodename(agent);
            XmlLog.Instance.Add("CmdProc:GetClearance():");
            foreach (XElement x in agents)
            {
                if (x.Element("Codename").Value == agent)
                {
                    return (string)x.Element("Clearance");
                }
            }
            return null; 
        }
        private void CmdHelp()
        {
            Send(s, "Help Submenu\r\n");
            SendLine("Your clearance is currently " + GetClearance(sp.agent));
            SendLine("Choose from the following:");
            string fmt = @"{0,-10}  {1,-10}  {2,-10}  {3,-10}";
            SendLine(String.Format(fmt, "codeword", "quit", "roll", "search"));
            SendLine(String.Format(fmt, "hack", "request", "tell", "help"));
            SendLine(String.Format(fmt, "email", "table", "", ""));
            SendLine("e.g.  table 1.27  -or- search mission PEANUT");
            SendLine("* All commands are case-sensitive");
        }
        private void SendDossier(string n)
        {
            // TODO CLEARANCE
            Send(s, "****************[ EDD S-4 Support of Mission CORE Interface ]******************\r\n");
            Send(s, "****************[ INCOMING TRANSMISSION FROM S-4 PERSONNEL  ]******************\r\n");
            Send(s, String.Format("Name    : {0,-25} Career (Primary): {1,-15} Career Level  : {2}\r\n",n,"Wheelman",3));
            Send(s, String.Format("Location: {0,-25} Mission Status  : {1,-15} Active Mission: {2}\r\n", "N/A", "ACTIVE", "OPERATION: TESTME"));

        }
        public MainForm Form { get { return _form; } set { _form = value; } }
        private void CmdSearch(string args)
        {

        }

        private void Send(Socket client, String data)
        {
            // Convert the string data to byte data using ASCII encoding.
            byte[] byteData = Encoding.ASCII.GetBytes(data);

            // Begin sending the data to the remote device.
            client.BeginSend(byteData, 0, byteData.Length, SocketFlags.None,
                new AsyncCallback(SendCallback), client);
        }
        private void Send(String data) { Send(s, data); }
        private void SendLine(Socket client, String data) { data += "\r\n"; Send(client, data); }
        private void SendLine(String data) { SendLine(s, data); }

        private void SendCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.
                Socket client = (Socket)ar.AsyncState;

                // Complete sending the data to the remote device.
                int bytesSent = client.EndSend(ar);
                //Console.WriteLine("Sent {0} bytes to server.", bytesSent);

                // Signal that all bytes have been sent.
                //sendDone.Set();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }



    }

    ///<summary>
    ///This is the XML-encapsulating class for our DB
    ///</summary>
    ///
    public class CLIDB
    {
        static string _fileName;
        XElement _x;

        static CLIDB _instance;
        public static CLIDB Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new CLIDB();
                return _instance;
            }
        }

        private CLIDB()
        {
            _fileName = @"Data Files\CLISearchData.xml";
            _x = XElement.Load(_fileName); // Root element
            XmlLog.Instance.Add("Loaded CLIDB log from " + _fileName);
        }

        //public Agent GetAgent(string name)
        //{
        //    IEnumerable<XElement> wpn =
        //        from el in _x.Elements("NAME")
        //        where (string)el.Element("NAME") == name
        //        select el;

        //    Agent newAgent = new Agent();
        //    foreach (XElement el in wpn)
        //    {

        //    }
        //    return newAgent;
        //}

        //public IEnumerable<XElement> FindAgentByName(string name)
        //{
        //    IEnumerable<XElement> wpn =
        //        from el in _x.Elements("NAME")
        //        select el;

        //    return wpn;
        //}
        //        public IEnumerable<XElement> FindWeaponByNode(string node)
        //        {
        //            // The event arg name is the name of the node
        //#if DEBUG
        //            XmlLog.Instance.Add("FindWeaponByNode: Looking for <NAME id=\" " + node + "\">");

        //#endif
        //            IEnumerable<XElement> wpn = 
        //                from x in _x.Elements("WEAPON")
        //                where (string)x.Element("NAME").Attribute("id") == node
        //                select x;

        //            return wpn;
        //        }

        public void Add(XElement newAgent)
        {
            _x.Add(newAgent);
            _x.Save(_fileName);
        }

        public void Clear()
        {
            _x.RemoveNodes();
            _x.Save(_fileName);
        }


        // Properties
        // Read-only
        public XElement Elements { get { return _x; } }



    }
}
